home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 5: The Fifth Dimension / 17 Bit - The Fifth Dimension (1995)(17 Bit Software)[!].iso / files / 3728.dms / 3728.adf / XPKDisk / device2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-09  |  12.5 KB  |  520 lines

  1. /*-
  2.  * DEVICE2.C
  3.  *
  4.  * The xpkdisk.device code that makes it a real Exec .device.
  5.  * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
  6.  *
  7.  * $Id: device2.c,v 1.5 1995/04/08 20:21:52 Rhialto Exp $
  8.  * $Log: device2.c,v $
  9.  * Revision 1.5  1995/04/08  20:21:52  Rhialto
  10.  * Add/correct version strings.
  11.  *
  12.  * Revision 1.4  1995/04/02  14:58:51  Rhialto
  13.  * Change #ifdef into #if.
  14.  * Update for DICE 3.0. Lots more casts.
  15.  *
  16.  * Revision 1.3  1993/11/08  13:11:15  Rhialto
  17.  * Add RCS tags.
  18.  *
  19.  *
  20.  * This code is (C) Copyright 1989-1995 by Olaf Seibert. All rights reserved.
  21.  * May not be used or copied without a licence.
  22. -*/
  23.  
  24. #include "xpkdisk.h"
  25. #include <exec/initializers.h>
  26.  
  27. #if DEBUG
  28. #   include "syslog.h"
  29. #else
  30. #   define    debug(x)
  31. #endif
  32. /* INDENT ON */
  33.  
  34. Prototype __geta4 DEV *Init(__A0 long segment, __D0 struct XpkDiskDevice *dev, __A6 struct ExecBase *execbase);
  35. Prototype __geta4 void DevOpen(__D0 ulong unitno, __D1 ulong flags, __A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  36. Prototype __geta4 long DevClose(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  37. Prototype __geta4 long DevExpunge(__A6 DEV *dev);
  38. Prototype __geta4 void DevBeginIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  39. Prototype __geta4 long DevAbortIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
  40.  
  41. Prototype void TermIO(struct IOStdReq *ioreq);
  42. Prototype void WakePort(struct MsgPort *port);
  43. Prototype __geta4 void UnitTask(void);
  44. Prototype void CMD_Invalid(struct IOStdReq *ioreq, UNIT *unit);
  45. Prototype void CMD_Stop(struct IOStdReq *ioreq, UNIT *unit);
  46. Prototype void CMD_Start(struct IOStdReq *ioreq, UNIT *unit);
  47. Prototype void CMD_Flush(struct IOStdReq *ioreq, UNIT *unit);
  48.  
  49. Prototype const char DevName[];
  50. Prototype const char idString[];
  51.  
  52. const char    DevName[] = "xpkdisk.device";
  53. const char    idString[] = "\0$VER: xpkdisk.device " STR(VERSION) "." STR(REVISION) "\r\n";
  54. static const char rcsId[] = "$Id: device2.c,v 1.5 1995/04/08 20:21:52 Rhialto Exp $";
  55.  
  56. /*
  57.  * Device commands:
  58.  */
  59.  
  60. void    (*const funcTable[]) (struct IOStdReq *, UNIT *) = {
  61.     CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
  62.     CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
  63.     TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
  64.     TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
  65.     TD_Remchangeint, TD_Getgeometry, TD_Eject,
  66. };
  67.  
  68. #define LAST_TD_COMM        TD_EJECT
  69.  
  70. long        SysBase;    /* Argh! A global variable! */
  71.  
  72. /*
  73.  * The Initialization routine is given a seglist pointer, the device
  74.  * base pointer, and the Exec base pointer. We are being called from
  75.  * InitResident. Exec has Forbid() for us during the call.
  76.  */
  77.  
  78.  
  79. __geta4 DEV    *
  80. Init(segment, dev, execbase)
  81. __A0 long    segment;
  82. __D0 DEV       *dev;
  83. __A6 struct ExecBase *execbase;
  84. {
  85.     SysBase = *(long *) 4;
  86. #if DEBUG
  87.     initsyslog();
  88.     debug(("seg %lx, dev %lx, sys %lx\n", segment, dev, execbase));
  89. #endif
  90.     if (DevInit(dev)) {
  91.     dev->xd_Seglist = segment;
  92.     debug(("Init done.\n"));
  93.     return dev;
  94.     }
  95.     FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
  96.     return NULL;
  97. }
  98.  
  99. /*
  100.  * Open is given the device pointer, unitno and flags.    Either return the
  101.  * device pointer or NULL.  Remove the DELAYED-EXPUNGE flag. Exec has
  102.  * Forbid() for us during the call.
  103.  */
  104.  
  105. __geta4 void
  106. DevOpen(unitno, flags, ioreq, dev)
  107. __D0 ulong    unitno;
  108. __D1 ulong    flags;
  109. __A1 struct IOStdReq *ioreq;
  110. __A6 DEV       *dev;
  111. {
  112.     UNIT       *unit;
  113.  
  114.     debug(("OpenDevice %lx unit %ld, flags %lx\n", dev, unitno, flags));
  115.     ++dev->dev_OpenCnt;
  116.     if (unitno >= XD_NUMUNITS)
  117.     goto error;
  118.  
  119.     if ((unit = dev->xd_Unit[unitno]) == NULL) {
  120.     debug(("Call UnitInit\n"));
  121.     if ((unit = UnitInit(dev, unitno)) == NULL)
  122.         goto error;
  123.     debug(("UnitInit succeeded: %x\n", unit));
  124.     dev->xd_Unit[unitno] = unit;
  125.     }
  126.     ioreq->io_Unit = (struct Unit *) unit;
  127.  
  128.     ++unit->xu_OpenCnt;
  129.     dev->dev_Flags &= ~LIBF_DELEXP;
  130.     ioreq->io_Error = 0;
  131.  
  132.     debug(("DevOpen: success\n"));
  133.     return;
  134.  
  135. error:
  136.     --dev->dev_OpenCnt;
  137.     ioreq->io_Error = IOERR_OPENFAIL;
  138.     debug(("DevOpen: fail\n"));
  139. }
  140.  
  141. /*
  142.  * Close is given the device pointer and the io request.  Be sure not to
  143.  * decrement the open count if already zero.    If the open count is or
  144.  * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
  145.  * return the seglist.    Otherwise we return NULL.
  146.  *
  147.  * Note that this routine never sets LIBF_DELEXP on its own.
  148.  *
  149.  * Exec has Forbid() for us during the call.
  150.  */
  151.  
  152. __geta4 long
  153. DevClose(ioreq, dev)
  154. __A1 struct IOStdReq *ioreq;
  155. __A6 DEV       *dev;
  156. {
  157.     UNIT       *unit;
  158.  
  159.     unit = (UNIT *) ioreq->io_Unit;
  160.     debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
  161.  
  162.     /*
  163.      * See if the unit is still in use. If not, close it down.
  164.      */
  165.  
  166.     if (unit->xu_OpenCnt && --unit->xu_OpenCnt == 0) {
  167.     dev->xd_Unit[unit->xu_UnitNr] = NULL;
  168.     UnitCloseDown(ioreq, dev, unit);
  169.     }
  170.     /*
  171.      * Make sure the ioreq is not used again.
  172.      */
  173.     ioreq->io_Unit = (void *) -1;
  174.     ioreq->io_Device = (void *) -1;
  175.  
  176.     if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
  177.     return NULL;
  178.     if (dev->dev_Flags & LIBF_DELEXP)
  179.     return DevExpunge(dev);
  180.     return NULL;
  181. }
  182.  
  183. /*
  184.  * We expunge the device and return the Seglist ONLY if the open count is
  185.  * zero. If the open count is not zero we set the DELAYED-EXPUNGE
  186.  * flag and return NULL.
  187.  *
  188.  * Exec has Forbid() for us during the call.  NOTE ALSO that Expunge might be
  189.  * called from the memory allocator and thus we CANNOT DO A Wait() or
  190.  * otherwise take a long time to complete (straight from RKM).
  191.  *
  192.  * Apparently RemLibrary(lib) calls our expunge routine and would therefore
  193.  * freeze if we called it ourselves.  As far as I can tell from RKM,
  194.  * DevExpunge(lib) must remove the device itself as shown below.
  195.  */
  196.  
  197. __geta4 long
  198. DevExpunge(dev)
  199. __A6 DEV       *dev;
  200. {
  201.     long        Seglist;
  202.  
  203.     if (dev->dev_OpenCnt) {
  204.     dev->dev_Flags |= LIBF_DELEXP;
  205.     return NULL;
  206.     }
  207.     Remove(&dev->dev_Node);
  208.     DevCloseDown(dev);          /* Should be quick! */
  209. #if DEBUG
  210.     uninitsyslog();
  211. #endif
  212.     Seglist = dev->xd_Seglist;
  213.     FreeMem((char *) dev - dev->dev_NegSize,
  214.         (long) dev->dev_NegSize + dev->dev_PosSize);
  215.     return Seglist;
  216. }
  217.  
  218. /*
  219.  * BeginIO entry point. We don't handle any QUICK requests, we just send
  220.  * the request to the proper unit to handle.
  221.  */
  222.  
  223. __geta4 void
  224. DevBeginIO(ioreq, dev)
  225. __A1 struct IOStdReq *ioreq;
  226. __A6 DEV       *dev;
  227. {
  228.     UNIT       *unit;
  229.  
  230.     /*
  231.      * Bookkeeping.
  232.      */
  233.     unit = (UNIT *) ioreq->io_Unit;
  234.     debug(("BeginIO: %x io %08lx dev %08lx u %08lx\n", ioreq->io_Command,
  235.         ioreq, dev, unit));
  236.  
  237.     /*
  238.      * See if the io command is within range.
  239.      */
  240.     if (STRIP(ioreq->io_Command) > LAST_TD_COMM)
  241.     goto NoCmd;
  242.  
  243. #if HANDLE_IO_QUICK
  244.     Forbid();                   /* Disable(); is a bit too strong for us. */
  245. #endif
  246.  
  247.     /*
  248.      * Process all immediate commands no matter what. Don't even require
  249.      * an exclusive lock on the unit.
  250.      */
  251.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  252.     goto Immediate;
  253.  
  254.     /*
  255.      * We don't handle any QUICK I/O since that only gives trouble with
  256.      * message ports and so. Other devices normally would include the code
  257.      * below.
  258.      */
  259. #if HANDLE_IO_QUICK
  260.     /*
  261.      * See if the user does not request QUICK IO. If not, it is likely to
  262.      * be async and therefore we don't do it sync.
  263.      */
  264.     if (!(ioreq->io_Flags & IOF_QUICK))
  265.     goto NoQuickRequested;
  266.  
  267.     /*
  268.      * See if the unit is STOPPED. If so, queue the msg.
  269.      */
  270.     if (unit->xu_Flags & UNITF_STOPPED)
  271.     goto QueueMsg;
  272.  
  273.     /*
  274.      * This is not an immediate command. See if the device is busy. If
  275.      * not, process the action in this (the caller's) context.
  276.      */
  277.     if (!BSET_ACTIVE(&unit->xu_Flags))
  278.     goto Immediate;
  279. #endif
  280.  
  281.     /*
  282.      * We need to queue the device. Clear the QUICK flag.
  283.      */
  284. QueueMsg:
  285.     ioreq->io_Flags &= ~IOF_QUICK;
  286. NoQuickRequested:
  287. #if HANDLE_IO_QUICK
  288.     Permit();                   /* Enable(); is a bit too strong for us. */
  289. #endif
  290.     PutMsg(&unit->xu_Port, &ioreq->io_Message);
  291.  
  292.     return;
  293.  
  294. Immediate:
  295. #if HANDLE_IO_QUICK
  296.     Permit();                   /* Enable(); is a bit too strong for us. */
  297. #endif
  298.     debug(("BeginIO: Immediate\n"));
  299.     ioreq->io_Error = TDERR_NoError;
  300.     PerformIO(ioreq, unit);
  301.     return;
  302.  
  303. NoCmd:
  304.     ioreq->io_Error = IOERR_NOCMD;
  305.     TermIO(ioreq);
  306.     return;
  307.  
  308. }
  309.  
  310. /*
  311.  * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
  312.  * commands that don't call TermIO, or call it multiple times, may not be
  313.  * properly handled unless you are careful. TD_ADDCHANGEINT and
  314.  * TD_REMCHANGEINT are obvious examples.
  315.  */
  316.  
  317. void
  318. TermIO(ioreq)
  319. register struct IOStdReq *ioreq;
  320. {
  321.     register UNIT  *unit;
  322.  
  323.     unit = (UNIT *) ioreq->io_Unit;
  324.     debug(("TermIO: io %08lx u %08lx %ld %ld\n", ioreq, unit,
  325.        ioreq->io_Actual, (long)ioreq->io_Error));
  326.  
  327. #if HANDLE_IO_QUICK
  328.     /*
  329.      * Since immediate commands don't even require an exclusive lock on
  330.      * the unit, don't unlock it.
  331.      */
  332.     if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
  333.     goto Immediate;
  334.  
  335.     /*
  336.      * We may need to turn the active (lock) bit off, but not if we are
  337.      * within the task.
  338.      */
  339.     if (unit->xu_Flags & UNITF_INTASK)
  340.     goto Immediate;
  341.  
  342.     unit->xu_Flags &= ~UNITF_ACTIVE;
  343.  
  344.     /*
  345.      * The task may have work to do that came in while we were processing
  346.      * in the caller's context.
  347.      */
  348.     if (unit->xu_Flags & UNITF_WAKETASK) {
  349.     unit->xu_Flags &= ~UNITF_WAKETASK;
  350.     WakePort(&unit->xu_Port);
  351.     }
  352. #endif
  353.  
  354. Immediate:
  355.     /*
  356.      * If the quick bit is still set then wen don't need to reply the msg
  357.      * -- just return to the user.
  358.      */
  359.  
  360.     if (!(ioreq->io_Flags & IOF_QUICK))
  361.     ReplyMsg(&ioreq->io_Message);
  362.  
  363.     return;
  364. }
  365.  
  366. /*
  367.  * AbortIO entry point. We try to abort IO here.
  368.  */
  369.  
  370. __geta4 long
  371. DevAbortIO(ioreq, dev)
  372. __A1 struct IOStdReq *ioreq;
  373. __A6 DEV       *dev;
  374. {
  375.     Forbid();
  376.     if (ioreq->io_Flags & IOF_QUICK ||
  377.     IMMEDIATE & (1L << STRIP(ioreq->io_Command))) {
  378.     Permit();
  379.     return 1;
  380.     } else {
  381.     Remove(&ioreq->io_Message.mn_Node);
  382.     Permit();
  383.     ioreq->io_Error = IOERR_ABORTED;
  384.     ReplyMsg(&ioreq->io_Message);
  385.  
  386.     return 0;
  387.     }
  388. }
  389.  
  390. void
  391. WakePort(port)
  392. register struct MsgPort *port;
  393. {
  394.     Signal(port->mp_SigTask, 1L << port->mp_SigBit);
  395. }
  396.  
  397. /*
  398.  * This is the main loop of the Unit tasks. It must be very careful with
  399.  * global data.
  400.  */
  401.  
  402. __geta4 void
  403. UnitTask(void)
  404. {
  405.     UNIT       *unit;
  406.     long        waitmask;
  407.     struct IOExtTD *ioreq;
  408.  
  409.     debug(("Start UnitTask\n"));
  410.     {
  411.     struct Task    *task;
  412.  
  413.     task = FindTask(NULL);
  414.     unit = (UNIT *) task->tc_UserData;
  415.     /* dev = unit->xu_Dev; */
  416.     task->tc_UserData = NULL;
  417.     debug(("task %lx unit %lx\n", task, unit));
  418.     }
  419.  
  420.     /*
  421.      * Now finish initializing the message ports and other signal things
  422.      */
  423.  
  424.     waitmask = UnitInit2(unit);
  425.     WakePort(&unit->xu_Port);
  426.  
  427.     for (;;) {
  428.     debug(("Task: Waiting...\n"));
  429.     Wait(waitmask);
  430.  
  431.     PollTimer(unit);
  432.  
  433.     /*
  434.      * See if we are stopped.
  435.      */
  436.     if (unit->xu_Flags & UNITF_STOPPED)
  437.         continue;
  438.  
  439. #if HANDLE_IO_QUICK
  440.     /*
  441.      * Lock the device. If it fails, we have set a flag such that the
  442.      * TermIO wakes us again.
  443.      */
  444.     unit->xu_Flags |= UNITF_WAKETASK;
  445.     if (BSET_ACTIVE(&unit->xu_Flags))
  446.         continue;
  447.  
  448.     unit->xu_Flags |= UNITF_INTASK;
  449. #endif
  450.  
  451.     while (ioreq = (struct IOExtTD *) GetMsg(&unit->xu_Port)) {
  452.         debug(("Task: io %08lx %lx\n", ioreq, (long)ioreq->iotd_Req.io_Command));
  453.         ioreq->iotd_Req.io_Error = 0;
  454.         if (ioreq->iotd_Req.io_Command == CMD_Die)
  455.         goto die;
  456.         PerformIO((&ioreq->iotd_Req), unit);
  457.     }
  458.  
  459. #if HANDLE_IO_QUICK
  460.     unit->xu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  461. #endif
  462.     }
  463.  
  464. die:
  465.     debug(("Aaargh! They stabbed me!\n"));
  466.     UnitCloseDown2(unit);
  467.     debug(("I'm gonna dieeeeeeeeeeee___________ .......\n"));
  468.     Forbid();
  469.     ioreq->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  470.     Signal((struct Task *)ioreq->iotd_Req.io_Message.mn_ReplyPort, SIGF_SINGLE);
  471.     /* fall off the end of the world */
  472. }
  473.  
  474. void
  475. CMD_Invalid(ioreq, unit)
  476. struct IOStdReq *ioreq;
  477. UNIT           *unit;
  478. {
  479.     ioreq->io_Error = IOERR_NOCMD;
  480.     TermIO(ioreq);
  481. }
  482.  
  483. void
  484. CMD_Stop(ioreq, unit)
  485. struct IOStdReq *ioreq;
  486. UNIT           *unit;
  487. {
  488.     unit->xu_Flags |= UNITF_STOPPED;
  489.     TermIO(ioreq);
  490. }
  491.  
  492. void
  493. CMD_Start(ioreq, unit)
  494. struct IOStdReq *ioreq;
  495. UNIT           *unit;
  496. {
  497.     unit->xu_Flags &= ~UNITF_STOPPED;
  498.     WakePort(&unit->xu_Port);
  499.     TermIO(ioreq);
  500. }
  501.  
  502. void
  503. CMD_Flush(ioreq, unit)
  504. struct IOStdReq *ioreq;
  505. UNIT           *unit;
  506. {
  507.     register struct IOStdReq *req;
  508.  
  509.     /* Flush our own command queue */
  510.     Forbid();
  511.     while (req = (struct IOStdReq *) GetMsg(&unit->xu_Port)) {
  512.     req->io_Error = IOERR_ABORTED;
  513.     ReplyMsg(&req->io_Message);
  514.     }
  515.     Permit();
  516.  
  517.     WakePort(&unit->xu_Port);
  518.     TermIO(ioreq);
  519. }
  520.